<template>
  <div class="employees-container">
    <div class="app-container">
      <page-tools>
        <template #left>
          <span>总记录数: {{ total }} 条</span>
        </template>

        <template #right>
          <el-button type="warning" size="small" @click="$router.push('/import?type=user')">excel导入</el-button>
          <el-button type="danger" size="small" :loading="downloadLoading" @click="handleDownload">excel导出</el-button>
          <el-button type="primary" size="small" @click="showDialog = true">新增员工</el-button>
        </template>
      </page-tools>

      <el-card style="margin-top: 10px;">
        <el-table v-loading="loading" border :data="list">
          <el-table-column label="序号" type="index" sortable="" />
          <el-table-column label="姓名" prop="username" sortable="" />
          <!-- 在员工列表中心显示图片 -->
          <el-table-column label="头像" prop="username" sortable="">
            <template #default="{row}">
              <img
                v-imgerror="defaultImage"
                class="staff"
                :src="row.staffPhoto || defaultImage"
                alt=""
                @click="clickShowCodeDialog(row.staffPhoto)"
              >
            </template>
          </el-table-column>
          <el-table-column label="手机号" prop="mobile" sortable="" />
          <el-table-column label="工号" prop="workNumber" sortable="" />
          <!-- 注意：后端返回数据不是我们想要的，要用formatter属性，格式化内容 -->
          <el-table-column :formatter="formatEmployment" label="聘用形式" prop="formOfEmployment" sortable="" />
          <el-table-column label="部门" prop="departmentName" sortable="" />
          <!-- 处理时间，封装函数，在这里使用默认插槽，调用方法 -->
          <el-table-column label="入职时间" prop="timeOfEntry" sortable="">
            <template #default="{row}">
              <!--vue2和vue3都能用 封装方法的形式 {{ formatDate(row.timeOfEntry) }} -->
              <!--
                注意：这种过滤器只有vue2能用，
                row.timeOfEntry  formatDate的第一个参数
                '**'  是formatDate的第二个参数s
              -->
              {{ row.timeOfEntry | formatDate('**') }}
            </template>
          </el-table-column>
          <el-table-column label="操作" sortable="" fixed="right" width="280">
            <template #default="scope">
              <el-button type="text" size="small" @click="$router.push(`/employees/detail/${scope.row.id}`)">查看</el-button>
              <el-button type="text" size="small">转正</el-button>
              <el-button type="text" size="small">调岗</el-button>
              <el-button type="text" size="small">离职</el-button>
              <el-button type="text" size="small" @click="editRole(scope.row.id)">角色</el-button>
              <!--
                按钮权限分配
                1、让按钮 禁用
                2、让按钮 隐藏
                3、让按钮 可以点击，但提示‘没有权限’
               -->
              <!-- <el-button type="text" size="small" :disabled="!checkPermission('bb')" @click="delEmployee(scope.row.id)">删除</el-button> -->
              <el-button v-if="checkPermission('bb')" type="text" size="small" @click="delEmployee(scope.row.id)">删除</el-button>
            </template>
          </el-table-column>

        </el-table>
        <!-- 分页组件 -->
        <div style="height: 60px; margin-top: 10px">
          <el-pagination
            :total="total"
            :current-page="page"
            :page-size="pageSize"
            layout="prev, pager, next"
            @current-change="handleCurrentChange"
          />
        </div>
      </el-card>
    </div>
    <!-- 弹出框组件 -->
    <add-employee
      :show-dialog.sync="showDialog"
      @getAddEmployee="getAddEmployee"
    />
    <!-- 分享展示, 预览的二维码的弹层 -->
    <el-dialog title="二维码" :visible="showCodeDialog" width="300px" @close="closeDialog">
      <el-row type="flex" justify="center">
        <canvas ref="myCanvas" />
      </el-row>
    </el-dialog>
    <!-- 角色弹层组件 -->
    <assign-role
      :show-role-dialog.sync="showRoleDialog"
      :user-id="userId"
    />
  </div>
</template>
<script>
import { reqGetEmployeeList, reqDelEmployee } from '@/api/employees'
import EmployeeEnum from '@/api/constant/employees'
import AddEmployee from './components/add-employee.vue'
import { formatDate } from '@/filters'
import QrCode from 'qrcode'
import AssignRole from './components/assign-role.vue'
import hello from '@/mixins/hello'
import permission from '@/mixins/permission'

// import dayjs from 'dayjs'
export default {
  name: 'Employees',
  components: {
    AddEmployee,
    AssignRole
  },
  // ----- 局部引入过滤器,全局在main.js中引入
  // filters: {
  //   formatDate: function(value, flag) {
  //     return dayjs(value).format(`YYYY${flag}MM${flag}DD`)
  //   }
  // },

  // 混入语法3步骤：1、创建一个js文件，并默认导出 2、在组件内导入 3、利用mixins: [hello]使用,
  //              (然后可以直接使用hello.js中的方法和属性了)
  // 注意：如果混入对象和组件有同名，优先组件的使用
  mixins: [hello, permission],

  data() {
    return {
      userId: '',
      showRoleDialog: false,
      showCodeDialog: false,
      showDialog: false,
      list: [],
      page: 1, // 当前页
      pageSize: 10, // 每页条数
      total: 0, // 总数
      loading: false,
      downloadLoading: false,
      defaultImage: 'https://pic.rmb.bdstatic.com/bjh/d9f2ac8b1eba6e5b3f968e0d5c07bc29.jpeg'
    }
  },
  created() {
    this.getEmployeeList()
    console.log(this.checkPermission())
    this.useMixins()
  },
  methods: {

    // 判断按钮权限 (也可以使用混入的语法)
    // checkPermission(flag) {
    //   // 返回的是true 说明有权限 返回的是false 没有权限
    //   return this.$store.getters.roles?.points.includes(flag)
    // },
    // 打开角色弹层
    editRole(id) {
      this.userId = id
      this.showRoleDialog = true
    },
    // 关闭二维码弹层
    closeDialog() {
      this.showCodeDialog = false
    },
    // 点击表格内头像显示弹层
    clickShowCodeDialog(url) {
      if (!url) return // 有图片才显示弹层
      this.showCodeDialog = true
      // 因为更新dom是异步的
      this.$nextTick(() => {
        // 如果这里 url 写的是网址, 就会跳转到对应网址 (二维码分享效果)
        QrCode.toCanvas(this.$refs.myCanvas, url)
      })
    },
    // 导出功能
    /**
     * 需求：
     * 导出功能具体需要要根据产品定义
     * 如果导出功能就导出当页， 用this.list就可以了
     * 人资这里需求 导出的都是全部数据，发请求 page - 1 pagesize - this.total
     *
     * 产品还可以定义要导出哪些字段 需求根据产品 他要什么你就给什么
     * const headersArr = ['姓名', '手机号', '入职日期', '聘用形式', '转正日期', '工号', '部门']
     */
    async handleDownload() {
      this.downloadLoading = true
      // 为什么要用import这种方式 - 性能优化
      /**
       * 导出功能并不是最常用（并不是所有人一用后台管理系统，一登录就导出表格） - 在你使用导出功能的再去加载这个vendor
       * 和路由懒加载一样，只要加载后，之后就缓存了
       */
      const { data: { rows }} = await reqGetEmployeeList(1, this.total)
      const multiHeader = [['姓名', '主要信息', '', '', '', '', '部门']] // 二维数组
      const tHeader = ['姓名', '手机号', '入职日期', '聘用形式', '转正日期', '工号', '部门']
      const merges = ['A1:A2', 'B1:F1', 'G1:G2'] // 需要和并哪些单元格
      const headersRelations = {
        '姓名': 'username',
        '手机号': 'mobile',
        '入职日期': 'timeOfEntry',
        '聘用形式': 'formOfEmployment',
        '转正日期': 'correctionTime',
        '工号': 'workNumber',
        '部门': 'departmentName'
      }
      const data = this.formatJson(rows, tHeader, headersRelations) // 二维数组
      import('@/vendor/Export2Excel').then(excel => {
        // const filterVal = ['id', 'title', 'author', 'pageviews', 'display_time']
        // const list = this.list
        excel.export_json_to_excel({
          // 合并单元格在这里导入
          multiHeader,
          merges,
          header: tHeader, // 表头，必填
          data // 表内容，必填
          // filename: '帅前的导出', // 标题
          // autoWidth: this.autoWidth,
          // bookType: this.bookType
        })
        this.downloadLoading = false
      })
    },
    /** 21日
     * 这个方法的作用 对象数组rows 转成 二维数组result
     * rows决定有几个嵌套的小数组 tHeader决定里面的小数组有几项
     * result 最终结果就是个二维数组
     */
    // 处理数据，转成二位数组
    formatJson(rows, tHeader, headersRelations) {
      const result = []
      rows.forEach(employeesObj => {
        const arr = []
        tHeader.forEach(col => {
          // 中文列 需要转成英文列
          const englishCol = headersRelations[col]
          // 拿到对象的键值对的值
          let val = employeesObj[englishCol]
          // 处理导出excel格式问题
          if (['timeOfEntry', 'correctionTime'].includes(englishCol)) {
            // 处理日期格式---引入、调用处理日期方法
            val = formatDate(val, '/')
          }
          if (englishCol === 'formOfEmployment') {
            // 处理聘用形式---
            val = EmployeeEnum.hireType.find(item => item.id === +val)?.value || '未知'
          }
          if (englishCol === 'departmentName') {
            // 处理部门格式
            val = val || '未知'
          }
          arr.push(val)
        })
        result.push(arr)
      })
      console.log(result)
      return result
    },
    // 封装员工列表
    async getEmployeeList() {
      this.loading = true
      const { data } = await reqGetEmployeeList(this.page, this.pageSize)
      console.log(data)
      const { total, rows } = data
      this.total = total
      this.list = rows
      this.loading = false
    },
    // 分页功能
    handleCurrentChange(newPage) {
      this.page = newPage
      this.getEmployeeList()
    },
    /**
     * 格式化表格内容：
     * row:每一行的数据 用的不多
     * column: 聘用形式这一列数据 用的不多
     * cellValue: 单元格的值 - 用的比较多 - 就是注入的数据对应字段的值 - 聘用形式的值
     * index:索引下标 - 用的不多
     *
     * 方法的返回值，就是最终我们处理格式化的内容
     */
    formatEmployment(row, column, cellValue, index) {
      // const obj = EmployeeEnum.hireType.find(item => item.id === cellValue)
      // 这里严谨判断，当能匹配到这个对象时，返回obj.value,否则返回‘未知’
      // return obj ? obj.value : '未知'

      // 或者利用  可选链运算符（?.）
      // ?. 运算符的功能类似于 . 链式运算符，不同之处在于，在引用为空 (nullish ) (null 或者 undefined) 的情况下不会引起错误，该表达式短路返回值是 undefined。
      return EmployeeEnum.hireType.find(item => item.id === +cellValue)?.value || '未知'
    },
    // 子传父通知父亲渲染页面
    getAddEmployee() {
      this.getEmployeeList()
      this.showDialog = false
    },
    // 删除员工
    async delEmployee(id) {
      await reqDelEmployee(id)
      if (this.list.length === 1 && this.page > 1) {
        this.page--
      }
      this.getEmployeeList()
      this.$message.success('删除成功')
    }

    // 处理时间格式 这种方法vue2和vue3都能用
    // formatDate(value) {
    //   return dayjs(value).format('YYYY~MM~DD')
    // }
  }
}
</script>

<style lang="scss" scoped>
.employees-container {
  .staff {
    width: 70px;
    height: 70px;
    border-radius: 50%;
  }
}
</style>
